﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO.Ports;
using System.ComponentModel;
using System.Threading;

namespace GSM
{
    /// <summary>
    /// 串口类
    /// </summary>
    public class SerialPortEx : SerialPort
    {
        public event Action<string> ReceivNewDataEvent;

        public AutoResetEvent ReceiveNow;
        /// <summary>
        /// 是否正在使用
        /// </summary>
        [DefaultValue(false)]
        public bool IsBusy { get; set; }

        public SerialPortEx(string portName, int baudRate)
            : base(portName, baudRate)
        {
            this.DtrEnable = true; //启用控制终端就续信号
            this.RtsEnable = true; //启用请求发送信号
            this.DataBits = 8;
            this.StopBits = StopBits.One;
            this.Parity = Parity.None;
            this.ReadTimeout = 500;
            this.WriteTimeout = 500;
            this.ReceiveNow = new AutoResetEvent(false);
        }




        /// <summary>
        /// 打开串口
        /// </summary>
        /// <returns></returns>
        public bool OpenPort()
        {
            if (this.IsOpen)
                return true;
            try
            {
                this.DataReceived += new SerialDataReceivedEventHandler(SerialPortEx_DataReceived);
                this.Open();
                return true;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public void SerialPortEx_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {

            try
            {
                if (e.EventType == SerialData.Eof)
                    return;
                if (this.IsBusy)
                {
                    this.ReceiveNow.Set();
                }
                else
                {
                    string output = this.ReadResponse();
                    this.ReceivedNewData(output);
                }

            }
            catch (Exception ex)
            {
                throw ex;
            }
        }


        private void ReceivedNewData(string msg)
        {
            if (this.ReceivNewDataEvent != null)
                this.ReceivNewDataEvent(msg);

        }

        /// <summary>
        /// 关闭串口
        /// </summary>
        public bool ClosePort()
        {

            if (!this.IsOpen)
                return true;
            try
            {
                this.Close();
                this.DataReceived -= this.SerialPortEx_DataReceived;
                return true;
            }
            catch (Exception ex)
            {
                throw new Exception("Close port failed", ex);
            }
        }



        /// <summary>
        /// 执行At指令
        /// </summary>
        /// <param name="command">At指令</param>
        /// <param name="responseTimeout"></param>
        /// <returns></returns>
        public string ExecCommand(string command, int responseTimeout)
        {
            try
            {
                this.IsBusy = true;
                this.DiscardOutBuffer();
                this.DiscardInBuffer();
                this.ReceiveNow.Reset();
                this.WriteLine(command);
                this.SerialPortIO(command);
                string output = this.ReadResponse(responseTimeout);
                return output;
            }
            catch (Exception ex)
            {
                throw new Exception("Execute command failed", ex);
            }
            finally
            {
                this.IsBusy = false;
            }

        }

        /// <summary>
        /// 直接读取串口输出
        /// </summary>
        /// <returns></returns>
        public string ReadResponse()
        {
            string buffer = string.Empty;
            try
            {
                for (int i = 0; i < 5; i++)
                {
                    string t = this.ReadExisting();
                    buffer += t;
                    if (!buffer.EndsWith("\r\nOK\r\n") && !buffer.EndsWith("\r\nERROR\r\n"))
                        Thread.Sleep(1000);
                    else
                        break;
                }
            }
            catch (Exception ex)
            {
                throw new Exception("Read response failed", ex);
            }
            finally
            {
                this.SerialPortIO(buffer);
            }           
            return buffer;

        }


        /// <summary>
        /// 在指定的超时内读取串口的输出
        /// </summary>
        /// <param name="timeout"></param>
        /// <returns></returns>
        public string ReadResponse(int timeout)
        {
            string buffer = string.Empty;
            try
            {
                if (ReceiveNow.WaitOne(timeout, false))
                {
                    for (int i = 0; i < 5; i++)
                    {
                        string t = this.ReadExisting();
                        buffer += t;

                        if (!buffer.EndsWith("\r\nOK\r\n") && !buffer.EndsWith("\r\n> ") && !buffer.EndsWith("\r\nERROR\r\n"))
                            Thread.Sleep(timeout);
                        else
                            break;
                    }
                }
            }
            catch (Exception ex)
            {
                throw new Exception("Read response failed", ex);
            }
            finally
            {
                this.SerialPortIO(buffer);
            }
            return buffer;

        }

        /// <summary>
        /// 串口输入与输出
        /// </summary>
        public event Action<string> OnSerialPortIO;

        private void SerialPortIO(string msg)
        {
            if (this.OnSerialPortIO != null)
                this.OnSerialPortIO(msg);
        }
    }
}
